// Copyright (c) 2015, Baidu.com, Inc. All Rights Reserved
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.

#ifndef STORAGE_LEVELDB_INCLUDE_DB_H_
#define STORAGE_LEVELDB_INCLUDE_DB_H_

#include <stdint.h>
#include <stdio.h>

#include "leveldb/iterator.h"
#include "leveldb/options.h"

namespace leveldb {

// Update Makefile if you change these
static const int kMajorVersion = 1;
static const int kMinorVersion = 12;

struct Options;
struct ReadOptions;
struct WriteOptions;
class WriteBatch;

// A range of keys
struct Range {
  Slice start;  // Included in the range
  Slice limit;  // Not included in the range

  Range() {}
  Range(const Slice& s, const Slice& l) : start(s), limit(l) {}
};

// A DB is a persistent ordered map from keys to values.
// A DB is safe for concurrent access from multiple threads without
// any external synchronization.
class DB {
 public:
  enum State { kNotOpen = 0, kOpened = 1, kShutdown1 = 2, kShutdown2 = 3 };

  // Open the database with the specified "name".
  // Stores a pointer to a heap-allocated database in *dbptr and returns
  // OK on success.
  // Stores NULL in *dbptr and returns a non-OK status on error.
  // Caller should delete *dbptr when it is no longer needed.
  static Status Open(const Options& options, const std::string& name, DB** dbptr);

  DB() {}
  virtual ~DB();

  // Abort all background work and do some clean work. DB is free to
  // to access during this process.
  virtual Status Shutdown1() = 0;
  // Do more clean work. Caller should not access the database after
  // this process start.
  virtual Status Shutdown2() = 0;

  // Set the database entry for "key" to "value".  Returns OK on success,
  // and a non-OK status on error.
  // Note: consider setting options.sync = true.
  virtual Status Put(const WriteOptions& options, const Slice& key, const Slice& value) = 0;

  // Remove the database entry (if any) for "key".  Returns OK on
  // success, and a non-OK status on error.  It is not an error if "key"
  // did not exist in the database.
  // Note: consider setting options.sync = true.
  virtual Status Delete(const WriteOptions& options, const Slice& key) = 0;

  // Apply the specified updates to the database.
  // Returns OK on success, non-OK on failure.
  // Note: consider setting options.sync = true.
  virtual Status Write(const WriteOptions& options, WriteBatch* updates) = 0;

  // If the database contains an entry for "key" store the
  // corresponding value in *value and return OK.
  //
  // If there is no entry for "key" leave *value unchanged and return
  // a status for which Status::IsNotFound() returns true.
  //
  // May return some other Status on an error.
  virtual Status Get(const ReadOptions& options, const Slice& key, std::string* value) = 0;

  // Return a heap-allocated iterator over the contents of the database.
  // The result of NewIterator() is initially invalid (caller must
  // call one of the Seek methods on the iterator before using it).
  //
  // Caller should delete the iterator when it is no longer needed.
  // The returned iterator should be deleted before this db is deleted.
  virtual Iterator* NewIterator(const ReadOptions& options) = 0;

  // Return a handle to the current DB state.  Iterators created with
  // this handle will all observe a stable snapshot of the current DB
  // state.  The caller must call ReleaseSnapshot(result) when the
  // snapshot is no longer needed.
  virtual const uint64_t GetSnapshot(uint64_t last_sequence = kMaxSequenceNumber) = 0;

  // Release a previously acquired snapshot.  The caller must not
  // use "snapshot" after this call.
  virtual void ReleaseSnapshot(uint64_t sequence_number) = 0;

  // Rollback to a spcific snapshot
  virtual const uint64_t Rollback(uint64_t snapshot_seq,
                                  uint64_t rollback_point = kMaxSequenceNumber) = 0;

  // DB implementations can export properties about their state
  // via this method.  If "property" is a valid property understood by this
  // DB implementation, fills "*value" with its current value and returns
  // true.  Otherwise returns false.
  //
  //
  // Valid property names include:
  //
  //  "leveldb.num-files-at-level<N>" - return the number of files at level <N>,
  //     where <N> is an ASCII representation of a level number (e.g. "0").
  //  "leveldb.stats" - returns a multi-line string that describes statistics
  //     about the internal operation of the DB.
  //  "leveldb.sstables" - returns a multi-line string that describes all
  //     of the sstables that make up the db contents.
  virtual bool GetProperty(const Slice& property, std::string* value) = 0;

  // For each i in [0,n-1], store in "sizes[i]", the approximate
  // file system space used by keys in "[range[i].start .. range[i].limit)".
  //
  // Note that the returned sizes measure file system space usage, so
  // if the user data compresses by a factor of ten, the returned
  // sizes will be one-tenth the size of the corresponding user data size.
  //
  // The results may not include the sizes of recently written data.
  virtual void GetApproximateSizes(const Range* range, int n, uint64_t* sizes) = 0;
  // tera-specific
  // size: db size, include mem, imm, all sst files
  // lgsize: each lg size, include all storage
  // mem_table_size: memtable's size, for analyzing memory usage.
  virtual void GetApproximateSizes(uint64_t* size, std::vector<uint64_t>* lgsize = NULL,
                                   uint64_t* mem_table_size = NULL) = 0;

  // tera-specific
  // result: each level's total file size
  virtual void GetCurrentLevelSize(std::vector<int64_t>* result) = 0;

  // Compact the underlying storage for the key range [*begin,*end].
  // In particular, deleted and overwritten versions are discarded,
  // and the data is rearranged to reduce the cost of operations
  // needed to access the data.  This operation should typically only
  // be invoked by users who understand the underlying implementation.
  //
  // begin==NULL is treated as a key before all keys in the database.
  // end==NULL is treated as a key after all keys in the database.
  // Therefore the following call will compact the entire database:
  //    db->CompactRange(NULL, NULL);
  virtual void CompactRange(const Slice* begin, const Slice* end, int lg_no = -1) = 0;

  // tera-specific
  // Too busy to write
  virtual bool BusyWrite() = 0;

  virtual void Workload(double* write_workload) = 0;

  virtual bool FindSplitKey(double ratio, std::string* split_key) = 0;
  virtual bool FindKeyRange(std::string* smallest_key = NULL, std::string* largest_key = NULL) = 0;

  virtual bool MinorCompact() = 0;

  // Add all sst files inherited from other tablets
  virtual void AddInheritedLiveFiles(std::vector<std::set<uint64_t> >* live) = 0;

  virtual bool ShouldForceUnloadOnError() { return false; }

  // Default : False,
  // Only activate the strategy for speeding up the process of shutdown DB.
  // Strategy : Always return True begin shutdown1 finished.
  virtual bool IsShutdown1Finished() const { return false; }

 private:
  // No copying allowed
  DB(const DB&);
  void operator=(const DB&);
};

// Destroy the contents of the specified database.
// Be very careful using this method.
Status DestroyDB(const std::string& name, const Options& options);

// If a DB cannot be opened, you may attempt to call this method to
// resurrect as much of the contents of the database as possible.
// Some data may be lost, so be careful when calling this function
// on a database that contains important information.
Status RepairDB(const std::string& dbname, const Options& options);

}  // namespace leveldb

#endif  // STORAGE_LEVELDB_INCLUDE_DB_H_
